// 数组
/**
 * 数组去重处理
 * 传入一个重复项很多的数组，返回一个去重之后的数组
 * eg: [a,a,a,b,b,b,c,c,c] => [a,b,c]
 * @param arr
 * @return Object
 */
export function unique(arr:Array<any>) {
  for (let i = 0; i < arr.length; i++) {
    for (let j = i + 1; j < arr.length; j++) {
      if (arr[i] === arr[j]) {
        //第一个等同于第二个，splice方法删除第二个
        arr.splice(j, 1);
        j--;
      }
    }
  }
  return arr;
}

/**
 * 数组去重
 * eg:
 *  toEqually([a,b,c,c,undefined],undefined) => [a,b,c,c]
 * @param arr 数组
 * @param key 判断类型 多出的重复的数据项
 */
export function toEqually(arr:Array<any>, key:string) {
  let newArr:Array<any> = [];
  for (let i of arr) {
    if (i !== key) {
      newArr.push(i);
    }
  }
  return newArr;
}


/**
 * 数组对象去重
 * eg： const arr = [{id:1,re:'foo'}, {id:2,re:'foo'}, {id:3,re:'foo2'}]
 *     uniqueArrayObj(arr,'re') => [{id:1,re:'foo'}, {id:3,re:'foo2'}]
 * @param array 数组对象
 * @param key 需要去重的特定数组对象属性
 * @return array:Array<Object>
 */

export function uniqueArrayObj(array:Array<Object>,key:any) {
  let result = [];
  let obj = {};
  for(let i =0; i < array.length; i++){
    // @ts-ignore
    if(!obj[array[i]?.[`${key}`]]){
      result.push(array[i]);
      // @ts-ignore
      obj[array[i]?.[`${key}`]] = true;
    }
  }
  return result
}


/**
 * 数组对象排序方法
 * eg:
 let data = [{name:'alis',key:2},{name:'alis2',key:3},{name:'alis3',key:4}]
 sortArr(data,'key','desc') => [{name:'alis3',key:4},{name:'alis2',key:3},{name:'alis',key:2}]
 * @param data 数组对象
 * @param key 对象属性
 * @param order 排序 asc / desc 正序倒序
 */
export function sortArr(data:Array<any>, key:string, order:string) {
  if (order === 'asc') {
    data.sort((a, b) => a[key] - b[key]);
  }
  if (order === 'desc') {
    data.sort((a, b) => b[key] - a[key]);
  }
  return data;
}

/**
 * 检查数组各项相等
 * @param array
 * @return boolean
 */
export function allEqual(array:Array<any>){
 return array.every(value => value === array[0])
}

/**
 * 判断几维数组
 * @param array
 * @return number
 */
export function isMultiArray(array:Array<any>) {
  let temp = 1
    for (let i=0;i<array.length;i++) {
      if(array[i] instanceof Array) {
        temp++;
        array = array[i];
        isMultiArray(array);
      }
    }
    return temp;
}


/**
 * 数组转csv格式,适合一维数组
 * @param array
 * @param delimiter 分割符
 * @return string
 */
export function arrayToCSV(array:Array<any>, delimiter:string = ',') {
  return array.map(value => `"${value}"`).join(`${delimiter}`+'\n')
}

/**
 *  求数组平均数
 * @param array
 * @return number
 */
export function average(array:Array<number>) {
  return array.reduce((acc,val) => acc + val,0) / array.length;
}

/**
 * 求数组项的最大值
 * @param array
 */
export function arrayMax(array:Array<number>) {
  return Math.max.apply(null,array)
}

/**
 * 求数组项的最小值
 * @param array
 */
export function arrayMin(array:Array<number>) {
  return Math.min.apply(null,array)
}

/**
 * 数组对象属性平均数
 * @param array 数组对象
 * @param obj 数组对象的键名
 * @return number
 */
export function averageObj(array:Array<object>,obj: string | Function) {
  // @ts-ignore
  return array.map(typeof obj === 'function' ? obj : val => val[obj]).reduce((acc, val) => acc + val, 0) / array.length;
}

/**
 * 去除数组中的无效/无用值
 * eg: compact([0, 1, false, 2, '', 3, 'a', 'e' * 23, NaN, 's', 34]); // [ 1, 2, 3, 'a', 's', 34 ]
 * @param array
 * @return array
 */

export function compact(array:Array<any>) {
  return array.filter(Boolean)
}

/**
 * 检测数值出现次数
 * eg: countOccurrences([1, 1, 2, 1, 2, 3], 1); // 3
 * @param array 检测的数组
 * @param key 检测的关键字
 * @return number 返回出现的次数
 */
export function countOccurrences(array:Array<any>,key:any) {
  return array.reduce((acc, val) => (val === key ? acc + 1 : acc), 0);
}

/**
 * 递归扁平化数组 多维数组转一维数组
 * eg: deepFlatten([1, [2], [[3], 4], 5]); // [1,2,3,4,5]
 * @param array
 * @return array
 */

export function deepFlatten(array:Array<any>):Array<any> {
  return [].concat(...array.map(value => (Array.isArray(value)) ? deepFlatten(value) : value))
}

/**
 * 寻找差异（并返回第一个数组独有的）
 * 此代码段查找两个数组之间的差异，并返回第一个数组独有的。
 * 无独有，返回第一个数组
 * difference([1, 2, 3], [1, 2, 4]); // [3]
 * @param firstArray
 * @param secondArray
 * @return Array
 */

export function difference(firstArray:Array<any>,secondArray:Array<any>) {
  const dif = new Set(secondArray);
  return firstArray.filter(val => !dif.has(val))
}


/**
 * 删除不符合条件的值
 * 此代码段从数组顶部开始删除元素，直到传递的函数返回为true
 * eg: console.log(dropWhile([1,2,3,4,5],  (n: number) => n >= 3))
 * @param array
 * @param func
 */

export function dropWhile(array:Array<any>,func:Function) {
  while (array.length > 0 && !func(array[0])) array = array.slice(1);
  return array;
}

/**
 * 返回数组中某值的所有索引
 * 可用于获取数组中某个值的所有索引，如果此值中未包含该值，则返回一个空数组。
 * eg: indexOfAll([1, 2, 3, 1, 2, 3], 1); // [0,3]
 *      indexOfAll([1, 2, 3], 4); // []
 * @param array 被检索的数组
 * @param value 查找值
 * @return array
 */
export function indexOfAll(array:Array<any>,value:Array<any>) {
  return array.reduce((acc, el, i) => (el === value ? [...acc, i] : acc), [])
}

/**
 * 两数组的交集
 * eg: intersection([1, 2, 3], [4, 3, 2]); // [2, 3]
 * @param firstArray
 * @param secondArray
 */
export function intersection(firstArray:Array<any>,secondArray:Array<any>) {
  const set = new Set(secondArray);
  return firstArray.filter(val => set.has(val));
}

/**
 * 两数组都符合条件的交集
 * 在对两个数组的每个元素执行了函数之后，返回两个数组中存在的元素列表。
 * eg: intersectionWith([2.1, 1.2], [2.3, 3.4], Math.floor)  // [2.1]
 * @param firstArray
 * @param secondArray
 * @param fn 自定义的函数条件
 * @return array
 */
export function intersectionWith(firstArray:Array<any>,secondArray:Array<any>,fn:Function) {
  // @ts-ignore
  const set = new Set(secondArray.map(fn));
  return firstArray.filter(val => set.has(fn(val)));
}

/**
 * 先比较后返回交集
 * eg:
 * const firstArray = [1, 1.2, 1.5, 3, 0]
 * const secondArray = [1.9, 3, 0, 3.9]
 * comparedIntersectionWith(firstArray,secondArray , (firstArray, secondArray) => Math.round(firstArray) === Math.round(secondArray))
 * => // [1.5, 3, 0]
 * @param firstArray
 * @param secondArray
 * @param comp 自定义的函数条件
 * @return array
 */

export function comparedIntersectionWith(firstArray:Array<any>,secondArray:Array<any>,comp:Function) {
  return  firstArray.filter(first => secondArray.findIndex(second => comp(first, second)) !== -1);
}

/**
 * 返回指定长度的升序数组
 * eg: ascendingLengthArray([1, 2, 3],1) => [1]
 *  ascendingLengthArray([1, 2, 3],2) => [1,2]
 * @param array 升序数组
 * @param length 要求升序的数组的长度,大于该数组的长度返回原数组
 * @return array 指定长度的数组
 */

export function ascendingLengthArray(array:Array<any>,length:number) {
  return [...array].sort((first, second) => first - second).slice(0, length)
}

/**
 * 生成两数之间指定长度的随机数组
 * eg: randomIntArrayInRange(12, 35, 10); // [ 34, 14, 27, 17, 30, 27, 20, 26, 21, 14 ]
 * @param min 生成数组区间的最小值
 * @param max 生成数组区间的最大值
 * @param length 生成数组的长度
 * @return array 生成的数组
 */
export function randomIntArrayInRange(min:number, max:number, length: number) {
  return  Array.from({ length: length }, () => Math.floor(Math.random() * (max - min + 1)) + min);
}

/**
 * 在指定数组中获取随机数
 * eg: randomItem([3, 7, 9, 11]); // 9
 * @param array 数组
 * @return any 返回数组内的任意一项
 */
export function randomItem(array:Array<any>) {
  return array[Math.floor(Math.random() * array.length)];
}

/**
 * 在指定数组中获取指定长度的随机数
 * 从数组中获取指定长度的随机数，直至穷尽数组。 使用Fisher-Yates算法对数组中的元素进行随机选择。
 * eg: sampleSize([1, 2, 3], 2); // [3,1]
 *     sampleSize([1, 2, 3], 4); // [2,3,1]
 * @param array
 * @param length
 */
export function sampleSize(array:Array<any>,length:number) {
  let len = array.length;
  while (len) {
    const i = Math.floor(Math.random() * len--);
    [array[len], array[i]] = [array[i], array[len]];
  }
  return array.slice(0, length);
}

/**
 * “洗牌” 数组
 * 使用Fisher-Yates算法随机排序数组的元素。
 * eg: shuffle([1, 2, 3]); // [2, 3, 1]
 * @param array
 * @return array
 */

export function shuffle(array:Array<any>) {
  let len = array.length;
  while (len) {
    const i = Math.floor(Math.random() * len--);
    [array[len], array[i]] = [array[i], array[len]];
  }
  return array;
}
















